//
//  WXSRecorderManger.m
//  SmartRecorderTest
//
//  Created by 王勇 on 2016/9/21.
//  Copyright © 2016年 王勇. All rights reserved.
//

#import "WXSRecorderManger.h"
#import "WXSAudioEditor.h"
#import "WXSSleepManager.h"

#import "WXSDreamTalkModel.h"

#import "WXAlert.h"

#import "WXSSleepInfoModel.h"

static const NSTimeInterval kMinimumMonitorInterval = 0.3;
static const NSTimeInterval kMaximumRecordingLength = 4.0;


//梦话分贝阈值
static const float kUpperThreshHold = -30.0;
static const float kLowerThreshHold = -35.0;

//梦话时间的延时（防止语音被中途截断）
static const float kTalkTimeDelay = 0.5;

@interface WXSRecorderManger()<AVAudioRecorderDelegate>

@property (nonatomic,strong)AVAudioRecorder *recorder;

@property (nonatomic,strong)WXSDreamTalkModel *range;

@property (nonatomic,strong)NSMutableArray <WXSDreamTalkModel*> *tempSleepTalkTimes;//记录每次梦话的开始结束时间（临时存储，每个录音文件录制后，赋值给sleeptalktimes，随后立即清空内容）

@property (nonatomic,strong)NSMutableArray <WXSDreamTalkModel*> *SleepTalkTimes;//记录每次梦话的开始结束时间（睡眠记录过程中持续保存，每个录音文件录制完成后，添加tempSleepTalkTimes的内容到本数组中。在睡眠结束后存入沙盒）

@property (nonatomic,strong)NSTimer *timer;

@property (nonatomic,assign)BOOL didDetectVoice;//是否检测到了说话声。

@property (nonatomic,strong)NSString *audioFilePath;//录音文件的存储位置


@end


static int i = 0;

NSInteger currentIndex = 0;
NSString *kCompletedRecordFilePath = nil;//测试音频剪裁用的路径
static WXSRecorderManger *manager = nil;
@implementation WXSRecorderManger{
    NSInteger isFirstLaunch;//是否是用户第一次使用APP。0表示“是”，1
}

+(instancetype)defaultManager{
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        manager = [[self alloc]init];
    });
    
    return manager;
}

#warning 可能需要完善
-(instancetype)init{
    self = [super init];
    if (self) {
       isFirstLaunch = [[NSUserDefaults standardUserDefaults]integerForKey:@"isFirstLaunch"];
    }
    return self;
}

#warning 需要完善
-(void)startRecordingWithFilePath:(NSString *)filePath completionHandler:(ManagerCompletionHandler)handler{
    BOOL isSuccessful = NO;
    self.isStoppedManually = NO;//新录音开始的时候，默认“没有手动结束录音"
    
    self.audioFilePath = filePath;
    
    if (self.tempSleepTalkTimes && self.tempSleepTalkTimes.count > 0) {
        [self.tempSleepTalkTimes removeAllObjects];
    }
    
    if (kCompletedRecordFilePath) {
        kCompletedRecordFilePath = nil;
    }
    
    if (i>0) {
        i = 0;
    }
    
    //设置音频会话
    [self configAudioSession];
    
    if ([self.recorder isRecording]) {
        return;
    }
    
    isSuccessful = [self.recorder recordForDuration:kMaximumRecordingLength];
    self.recorder.meteringEnabled = YES;
    if (isSuccessful) {
        self.timer.fireDate = [NSDate distantPast];
    }
    
    if (handler) {
        handler(isSuccessful);
    }
}

-(void)stopRecording:(ManagerCompletionHandler)handler{
    self.isStoppedManually = YES;
    [self.recorder stop];
    
    [self.timer invalidate];
    self.timer = nil;
}

-(void)browseRecordFileWithPath:(NSString *)filePath{
    
}

//-(void)removeFileAtPath:(NSString *)filePath{
//    NSError *error = nil;
//    NSFileManager *fileManager = [NSFileManager defaultManager];
//    [fileManager removeItemAtPath:filePath error:&error];
//    if (error) {
//        NSLog(@"Failed to delete file. Error:%@",error.localizedDescription);
//    }else{
//        NSLog(@"Removed file successfully!");
//    }
//}



#pragma mark - AVAudioRecorderDelegate
-(void)audioRecorderDidFinishRecording:(AVAudioRecorder *)recorder successfully:(BOOL)flag{
    
    [self handleUnfinishedSleepTalk];
    
    kCompletedRecordFilePath = [[self.recorder.url path]copy];
    
    currentIndex = self.SleepTalkTimes.count;
    
    [self.SleepTalkTimes addObjectsFromArray:[self.tempSleepTalkTimes copy]];
    
    //子线程中去处理完成的录音文件
    [self performSelectorInBackground:@selector(cutSleepTalkAudioFile) withObject:nil];
    
    self.recorder = nil;
    
    //如果不是人为停止录音，继续录下一段
    if (!self.isStoppedManually) {
        
        //在开始新的一轮录音前，删除本轮录音中的临时梦话数组
        if (self.tempSleepTalkTimes.count > 0) {
//            NSLog(@"本次录音共捕获梦话：%@",self.tempSleepTalkTimes);
            
            [self.tempSleepTalkTimes removeAllObjects];
//            NSLog(@"^^^^^^^^address of self.sleeptimes Array:%p",self.tempSleepTalkTimes);
        }
        
        [self.recorder recordForDuration:kMaximumRecordingLength];
        self.recorder.meteringEnabled = YES;
//        NSLog(@"************开始了新的录音");
    }else{//人为终止录音，通知保存录音模型
        NSNotification *saveAudioNotification = [[NSNotification alloc]initWithName:@"SaveAudioModelsNotification" object:self.SleepTalkTimes userInfo:@{@"sleepTalks":self.SleepTalkTimes}];
        [[NSNotificationCenter defaultCenter]postNotification:saveAudioNotification];
    }
}

-(void)audioRecorderEncodeErrorDidOccur:(AVAudioRecorder *)recorder error:(NSError *)error{
    NSLog(@"Encoding error occured! error info:%@",error.localizedDescription);
    [WXAlert showAlert:[NSString stringWithFormat:@"录音遇到错误！错误代码：%ld",(long)error.code] buttonAction:nil];
}

#pragma mark - Private

#warning 需要进一步处理
-(void)configAudioSession {
    AVAudioSession *session = [AVAudioSession sharedInstance];
    
    //获取录音许可
    if (isFirstLaunch<= 0) {//第一次启用
        [session requestRecordPermission:^(BOOL granted) {
            self.allowedToRecord = granted;
        }];
        isFirstLaunch = 1;
        
        [[NSUserDefaults standardUserDefaults]setInteger:isFirstLaunch forKey:@"isFirstLaunch"];
        [[NSUserDefaults standardUserDefaults]synchronize];
    }
    
    //检查录音权限是否获得
    switch (session.recordPermission) {
        case AVAudioSessionRecordPermissionDenied:
            [WXAlert showAlert:@"麦克风权限已被禁用，将无法记录梦话。请到“设置-隐私-麦克风”中授权麦克风。" buttonAction:nil];
            break;
        case AVAudioSessionRecordPermissionUndetermined:{
            [session requestRecordPermission:^(BOOL granted) {
                self.allowedToRecord = granted;
            }];
        }
            break;
        default:
//            NSLog(@"麦克风获得授权！");
            break;
    }
    
    [session setCategory:AVAudioSessionCategoryPlayAndRecord error:nil];
    [session setActive:YES error:nil];
}

-(NSMutableDictionary*)configRecorderSettings{
    NSMutableDictionary *settings = [NSMutableDictionary dictionary];
    [settings setObject:@(kAudioFormatLinearPCM) forKey:AVFormatIDKey];
    //设置录音采样率，8000是电话采样率，对于一般录音已经够了
    [settings setObject:@(8000) forKey:AVSampleRateKey];
    //设置通道,这里采用单声道
    [settings setObject:@(1) forKey:AVNumberOfChannelsKey];
    //每个采样点位数,分为8、16、24、32
    [settings setObject:@(8) forKey:AVLinearPCMBitDepthKey];
    //是否使用浮点数采样
    [settings setObject:@(YES) forKey:AVLinearPCMIsFloatKey];
    
    return settings;
}

#warning 需要进一步处理
-(NSURL*)configSavePathURL{
    NSString *path = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES).lastObject;
    NSString *filePath = [path stringByAppendingPathComponent:[NSString stringWithFormat:@"MyFirstAudio_%d.caf",i]];
//    NSLog(@"filepath:%@",filePath);
    i++;
    
    NSURL *fileURL = [NSURL fileURLWithPath:filePath];
    return  fileURL;
}

/**
 *  处理在每个录音文件结尾没有说完的梦话
 */
-(void)handleUnfinishedSleepTalk{
    //取得未经懒加载的实例变量
    if (_range && _range.endTime == -1) {
        _range.endTime = kMaximumRecordingLength;
        [self.tempSleepTalkTimes addObject:_range];
        _range = nil;
    }
}

-(void)cutSleepTalkAudioFile{
    NSObject *lock = self;
    @synchronized(lock) {
        NSString *filePath = [NSString stringWithFormat:@"%@",kCompletedRecordFilePath];
        
        NSString *tempExportPath = self.audioFilePath;
        NSString *exportPath = [tempExportPath stringByAppendingPathComponent:@"我的录音"];
        
        NSError *error = nil;
        [[NSFileManager defaultManager]createDirectoryAtPath:exportPath withIntermediateDirectories:NO attributes:nil error:&error];
        if (error) {
//            NSLog(@"error occured while creating new directory:%@",error.localizedDescription);
        }
        
        //梦话共有几段
        __block NSInteger sleepTalkCount = self.tempSleepTalkTimes.count;
        WXSAudioEditor *editor = [WXSAudioEditor shareAudioEdit];
        [editor editAudiofileAtPath:filePath exportPath:exportPath WithTimeRanges:self.SleepTalkTimes   currentIndex:currentIndex completionHandler:^(BOOL ret) {
            if (ret) {
                NSLog(@"cut success!");
                
                if (sleepTalkCount > 0) {
                    sleepTalkCount--;
                }
            }
            
            
            if (sleepTalkCount == 0) {
                NSError *removeError = nil;
                BOOL didDelete = [[NSFileManager defaultManager]removeItemAtPath:filePath error:&removeError];
                if (didDelete) {
//                    NSLog(@"delete success!");
                }else {
//                    NSLog(@"%@",removeError.localizedDescription);
                }
            }
        }];
    }
}

-(void)monitorVoicePower{
    [self.recorder updateMeters];
    float powerDecibel = [self.recorder averagePowerForChannel:0];
    
    //噪音强度超限提示（梦话开始）
    if (powerDecibel>= kUpperThreshHold && self.didDetectVoice == NO) {
        WXSDreamTalkModel *range = [[WXSDreamTalkModel alloc]init];
        range.recordStartTime = [NSDate date];
        
//        NSNotification *enterShallowNotification = [[NSNotification alloc]initWithName:@"EnterShallowNotification" object:self userInfo:nil];
//        [[NSNotificationCenter defaultCenter]postNotification:enterShallowNotification];
        if (self.recorder.currentTime >= kTalkTimeDelay) {
            range.beginTime = self.recorder.currentTime - kTalkTimeDelay;
        }else{
            range.beginTime = 0;
        }
        
        self.range = range;
        self.didDetectVoice = YES;
        NSLog(@"Dream talk began");

        [[WXSSleepManager defaultManager]enterShallowSleepStatus:nil];
    }
    
    if (powerDecibel < kLowerThreshHold && self.didDetectVoice) {
        self.range.recordEndTime = [NSDate date];
        self.range.endTime = self.recorder.currentTime + kTalkTimeDelay;
        [self.tempSleepTalkTimes addObject:self.range];
        
        self.range = nil;//抛弃这个range。这样下次调用setter方法时beginTime和endTime就会重置
        
//        NSLog(@"Dream talk ended");
        self.didDetectVoice = NO;
    }
}


#pragma mark Setter & Getter

-(AVAudioRecorder *)recorder{
    if (!_recorder) {
        NSURL *pathURL = [self configSavePathURL];
        NSMutableDictionary *settings = [self configRecorderSettings];
        
        NSError *error = nil;
        _recorder = [[AVAudioRecorder alloc]initWithURL:pathURL settings:settings error:&error];
        _recorder.delegate = self;
        
        if (error) {
//            NSLog(@"error occured! %@",error.localizedDescription);
            [WXAlert showAlert:[NSString stringWithFormat:@"无法录音！错误代码：%ld",(long)error.code] buttonAction:nil];
            return nil;
        }
    }
    return _recorder;
}

-(NSTimer *)timer{
    if (!_timer) {
        _timer = [NSTimer scheduledTimerWithTimeInterval:kMinimumMonitorInterval target:self selector:@selector(monitorVoicePower) userInfo:nil repeats:YES];
    }
    return _timer;
}

-(NSMutableArray<WXSDreamTalkModel *> *)tempSleepTalkTimes{
    if (!_tempSleepTalkTimes) {
        _tempSleepTalkTimes = [NSMutableArray array];
    }
    return _tempSleepTalkTimes;
}

-(NSMutableArray<WXSDreamTalkModel *> *)SleepTalkTimes{
    if (!_SleepTalkTimes) {
        _SleepTalkTimes = [NSMutableArray array];
    }
    
    return _SleepTalkTimes;
}

-(WXSDreamTalkModel *)range{
    if (!_range) {
        _range = [[WXSDreamTalkModel alloc]init];
    }
    return _range;
}
@end
